package com.example.androidone.player;

import static android.media.MediaFormat.KEY_BIT_RATE;
import static android.media.MediaFormat.KEY_FRAME_RATE;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Build;
import android.util.Log;
import android.view.Surface;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Queue;
import java.util.LinkedList;
import androidx.annotation.NonNull;

import com.example.androidone.utils.Constants;

public class VideoDecoder {
    private static final String TAG = "VideoDecoder";
    private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_HEVC;
    private static final int MAX_QUEUE_SIZE = 10;

    // 视频配置常量
    private static final int TARGET_BITRATE = 20_000_000; // 20Mbps
    private static final int TARGET_FRAMERATE = 30;
    private static final int I_FRAME_INTERVAL = 1;
    private static final int BUFFER_SIZE_MULTIPLIER = 4;

    private int surfaceWidth = Constants.VIDEO_WIDTH;
    private int surfaceHeight = Constants.VIDEO_HEIGHT;

    private MediaCodec decoder;
    private Surface outputSurface;
    private boolean isDecoding = false;
    private final Queue<byte[]> inputQueue = new LinkedList<>();
    private final Object lock = new Object();
    private ByteBuffer[] inputBuffers;
    private ByteBuffer[] outputBuffers;
    private static final int LOG_THRESHOLD = 100;
    private int droppedFrameCount = 0;

    private final MediaCodec.Callback callback = new MediaCodec.Callback() {
        @Override
        public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
            ByteBuffer inputBuffer;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                inputBuffer = codec.getInputBuffer(index);
            } else {
                inputBuffer = inputBuffers[index];
            }

            if (inputBuffer != null) {
                synchronized (lock) {
                    byte[] data = inputQueue.poll();
                    if (data != null) {
                        try {
                            inputBuffer.clear();
                            inputBuffer.put(data);
                            long presentationTime = System.nanoTime() / 1000;
                            int flags = 0;
                            // 对于 VPS/SPS/PPS，设置 BUFFER_FLAG_CODEC_CONFIG 标志
                            if (data.length > 4 && (data[4] >> 1 & 0x3F) >= 32) {
                                flags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
                            }
                            codec.queueInputBuffer(index, 0, data.length, presentationTime, flags);
                            Log.d(TAG, "Queued buffer size: " + data.length + ", flags: " + flags);
                        } catch (Exception e) {
                            Log.e(TAG, "Error queuing input buffer", e);
                        }
                    } else {
                        codec.queueInputBuffer(index, 0, 0, 0, 0);
                    }
                }
            }
        }

        @Override
        public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index,
                                            @NonNull MediaCodec.BufferInfo info) {
            try {
                Log.d(TAG, "Output buffer available, size: " + info.size + ", flags: " + info.flags);
                codec.releaseOutputBuffer(index, true);
            } catch (Exception e) {
                Log.e(TAG, "Error releasing output buffer", e);
            }
        }

        @Override
        public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
            Log.e(TAG, "Decoder error: " + e.getMessage());
            synchronized (lock) {
                isDecoding = false;
                if (decoder != null) {
                    try {
                        decoder.stop();
                        decoder.release();
                    } catch (Exception re) {
                        Log.e(TAG, "Error releasing decoder", re);
                    }
                    decoder = null;
                }
            }
        }
        @Override
        public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
            Log.d(TAG, "Output format changed: " + format);
        }
    };

    public void init(Surface surface, int width, int height) {
        try {
            this.outputSurface = surface;
            this.surfaceWidth = Constants.VIDEO_WIDTH;
            this.surfaceHeight = Constants.VIDEO_HEIGHT;

            MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, surfaceWidth, surfaceHeight);

            // 强制使用软件解码器
            decoder = MediaCodec.createByCodecName("OMX.google.hevc.decoder");
            Log.d(TAG, "Created software decoder: " + decoder.getCodecInfo().getName());

            // 设置基础参数
            format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, surfaceWidth * surfaceHeight * 3 / 2);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);

            // 不要设置 CSD 数据，让解码器自己从流中解析
            decoder.configure(format, surface, null, 0);
            decoder.setCallback(callback);
            decoder.start();
            isDecoding = true;

            Log.d(TAG, "Successfully initialized decoder with format: " + format);
        } catch (Exception e) {
            Log.e(TAG, "Failed to initialize decoder", e);
            isDecoding = false;
            if (decoder != null) {
                decoder.release();
                decoder = null;
            }
        }
    }

    public void decode(byte[] data) {
        if (!isDecoding || data == null) {
            Log.d(TAG, "Skipping decode: isDecoding=" + isDecoding + ", data=" + (data != null));
            return;
        }

        // 添加起始码
        byte[] startCode = {0, 0, 0, 1};
        byte[] nalUnit = new byte[startCode.length + data.length];
        System.arraycopy(startCode, 0, nalUnit, 0, startCode.length);
        System.arraycopy(data, 0, nalUnit, startCode.length, data.length);

        synchronized (lock) {
            if (inputQueue.size() < MAX_QUEUE_SIZE) {
                inputQueue.offer(nalUnit);
                Log.d(TAG, "Queue size: " + inputQueue.size() + ", NAL size: " + nalUnit.length);
            } else {
                droppedFrameCount++;
                if (droppedFrameCount % LOG_THRESHOLD == 0) {
                    Log.w(TAG, "Queue full, dropped frames: " + droppedFrameCount);
                }
            }
        }
    }

    private void handleQueueOverflow() {
        droppedFrameCount++;
        if (inputQueue.size() > MAX_QUEUE_SIZE * 0.9) {
            for (int i = 0; i < MAX_QUEUE_SIZE/2; i++) {
                inputQueue.poll();
            }
        }
        if (droppedFrameCount % LOG_THRESHOLD == 0) {
            Log.w(TAG, "Queue full, dropped frames: " + droppedFrameCount);
        }
    }

    public void release() {
        isDecoding = false;
        if (decoder != null) {
            try {
                decoder.stop();
                decoder.release();
            } catch (Exception e) {
                Log.e(TAG, "Error releasing decoder", e);
            }
            decoder = null;
        }
        synchronized (lock) {
            inputQueue.clear();
        }
        Log.d(TAG, "Decoder released");
    }
}